package c.a.md.androidvideo;

import android.Manifest;
import android.app.ActivityManager;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.os.Environment;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;

public class AudioActivity extends AppCompatActivity
{

    private byte mBuffer[];
    private long startRecorderTime, stopRecorderTime;

    private Button recordBtn, playBtn, jumpBtn;
    private TextView statues;

    private boolean mIsRecording;
    private boolean mIsPlaying;

    private AudioRecord mAudioRecord;
    private int bufferSize;
    private FileInputStream fis;
    private File mAudioRecordFile;
    private FileOutputStream mFileOutputStream;

    private int BUFFER_SIZE = 1024;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_audio);

        recordBtn = findViewById(R.id.start_or_stop);
        playBtn = findViewById(R.id.play_or_stop);
        jumpBtn = findViewById(R.id.jump);
        statues = findViewById(R.id.statues);

        recordBtn.setOnClickListener(new L());
        playBtn.setOnClickListener(new L());
        jumpBtn.setOnClickListener(new L());

        check();

        //创建录音文件
        mAudioRecordFile = new File(getExternalFilesDir(null).getAbsolutePath() + "1.pcm");
    }

    private void check()
    {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED)
        {
            ActivityCompat.requestPermissions(this, new String[]{
                    Manifest.permission.RECORD_AUDIO,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    Manifest.permission.READ_EXTERNAL_STORAGE}, 21);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)
    {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 21)
        {

        }
    }

    private boolean doStart()
    {
        try
        {
            //记录开始录音时间
            startRecorderTime = SystemClock.uptimeMillis();

            if (mAudioRecordFile.exists())
                mAudioRecordFile.delete();

            mAudioRecordFile.createNewFile();

            //创建文件输出流
            mFileOutputStream = new FileOutputStream(mAudioRecordFile);
            //配置AudioRecord
            int audioSource = MediaRecorder.AudioSource.MIC;
            //所有android系统都支持
            int sampleRate = 44100;
            //单声道输入
            int channelConfig = AudioFormat.CHANNEL_IN_MONO;
            //PCM_16是所有android系统都支持的
            int autioFormat = AudioFormat.ENCODING_PCM_16BIT;
            //计算AudioRecord内部buffer最小
            int minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, autioFormat);
            //buffer不能小于最低要求，也不能小于我们每次我们读取的大小。
            mAudioRecord = new AudioRecord(audioSource, sampleRate, channelConfig, autioFormat, Math.max(minBufferSize, BUFFER_SIZE));

            //开始录音
            mAudioRecord.startRecording();

            mBuffer = new byte[1024];
            runOnUiThread(new Runnable()
            {
                @Override
                public void run()
                {
                    recordBtn.setText("暂停录音");
                }
            });
            //循环读取数据，写入输出流中
            while (mIsRecording)
            {
                //只要还在录音就一直读取
                int read = mAudioRecord.read(mBuffer, 0, 1024);
                if (read <= 0)
                {
                    return false;
                } else
                {
                    mFileOutputStream.write(mBuffer, 0, read);
                }
            }

            //退出循环，停止录音，释放资源
            stopRecorder();

        } catch (Exception e)
        {
            e.printStackTrace();
            return false;
        } finally
        {
            if (mAudioRecord != null)
            {
                mAudioRecord.release();
            }
        }
        return true;
    }

    /**
     * 开始录音
     */
    private void startRecorder()
    {
        new Thread()
        {
            @Override
            public void run()
            {
                if (!doStart()) recorderFail();
            }
        }.start();
    }

    /**
     * 停止录音
     */
    private void stopRecorder()
    {
        new Thread()
        {
            @Override
            public void run()
            {
                if (!doStop()) recorderFail();
            }
        }.start();
    }

    private boolean recorderFail()
    {
        runOnUiThread(new Runnable()
        {
            @Override
            public void run()
            {
                statues.setText("录取失败，请重新录入");
            }
        });
        mIsRecording = false;
        return false;
    }

    private boolean doStop()
    {
        mIsRecording = false;

        if(mAudioRecord == null)
            return false;

        //停止录音，关闭文件输出流
        mAudioRecord.stop();
        mAudioRecord.release();
        mAudioRecord = null;
        //记录结束时间，统计录音时长
        stopRecorderTime = SystemClock.uptimeMillis();
        //大于3秒算成功，在主线程更新UI
        final int send = (int) (stopRecorderTime - startRecorderTime) / 1000;
        if (send > 3)
        {
            runOnUiThread(new Runnable()
            {
                @Override
                public void run()
                {
                    statues.setText("录音成功：" + send + "秒");
                    recordBtn.setText("开始录音");
                }
            });
        } else
        {
            recorderFail();
            return false;
        }
        return true;
    }

    /**
     * 播放声音
     *
     */
    public void play()
    {
        if (!mIsPlaying)
        {
            mIsPlaying = true;

            playBtn.setText("停止播放");
            doPlay(mAudioRecordFile);
        }
    }

    private void doPlay(File audioFile)
    {
        if (audioFile != null)
        {
            //配置播放器
            //音乐类型，扬声器播放
            int streamType = AudioManager.STREAM_MUSIC;
            //录音时采用的采样频率，所以播放时同样的采样频率
            int sampleRate = 44100;
            //单声道，和录音时设置的一样
            int channelConfig = AudioFormat.CHANNEL_OUT_MONO;
            //录音时使用16bit，所以播放时同样采用该方式
            int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
            //流模式
            int mode = AudioTrack.MODE_STREAM;

            //计算最小buffer大小
            int minBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat);

            //构造AudioTrack  不能小于AudioTrack的最低要求，也不能小于我们每次读的大小
            AudioTrack audioTrack = new AudioTrack(streamType, sampleRate, channelConfig, audioFormat,
                    Math.max(minBufferSize, BUFFER_SIZE), mode);

            //从文件流读数据
            FileInputStream inputStream = null;
            try
            {
                //循环读数据，写到播放器去播放
                inputStream = new FileInputStream(audioFile);
                mBuffer = new byte[1024];

                //循环读数据，写到播放器去播放
                int read;
                //只要没读完，循环播放
                while ((read = inputStream.read(mBuffer)) > 0)
                {
                    int ret = audioTrack.write(mBuffer, 0, read);
                    audioTrack.flush();
                    //检查write的返回值，处理错误
                    switch (ret)
                    {
                        case AudioTrack.ERROR_INVALID_OPERATION:
                        case AudioTrack.ERROR_BAD_VALUE:
                        case AudioManager.ERROR_DEAD_OBJECT:
                            playFail();
                            return;
                        default:
                            break;
                    }
                    audioTrack.play();
                }

            } catch (Exception e)
            {
                e.printStackTrace();
                //读取失败
                playFail();
            } finally
            {
                mIsPlaying = false;
                //关闭文件输入流
                if (inputStream != null)
                {
                    closeStream(inputStream);
                }
                statues.setText("播放完成");
                playBtn.setText("开始播放");
                //播放器释放
                resetQuietly(audioTrack);
            }
        }
    }

    /**
     * 关闭输入流
     *
     * @param inputStream
     */
    private void closeStream(FileInputStream inputStream)
    {
        try
        {
            inputStream.close();
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    private void resetQuietly(AudioTrack audioTrack)
    {
        try
        {
            audioTrack.stop();
            audioTrack.release();
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    /**
     * 播放失败
     */
    private void playFail()
    {
        runOnUiThread(new Runnable()
        {
            @Override
            public void run()
            {
                statues.setText("播放失败");
                playBtn.setText("开始播放");
            }
        });
    }

    @Override
    protected void onDestroy()
    {
        doStop();
        super.onDestroy();
    }

    class L implements View.OnClickListener
    {

        @Override
        public void onClick(View v)
        {
            switch (v.getId())
            {
                case R.id.start_or_stop:

                    mIsRecording = !mIsRecording;

                    if (mIsRecording)
                        startRecorder();
                    else
                        stopRecorder();
                    break;
                case R.id.play_or_stop:
                    play();
                    break;
                case R.id.jump:
                    startActivity(new Intent(AudioActivity.this, RecordAndPlayActivity.class));
                    break;
            }
        }
    }
}
